package com.project.scheduled.service.impl;
/**
 * 定时调度
 *
 */

import com.project.scheduled.entity.ScheduledConfig;
import com.project.scheduled.service.BusinessLogicService;
import com.project.scheduled.service.ScheduledConfigService;
import com.project.scheduled.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Slf4j
@Component
public class DynamicScheduledConfigurer implements SchedulingConfigurer {
    @Resource
    private ScheduledConfigService scheduledConfigService;

    @Resource
    private TaskScheduler taskScheduler;
    // 存储已注册的任务，避免重复注册
    private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(taskScheduler);
        taskRegistrar.addFixedDelayTask(this::refreshTasks, 600000); // 每10分钟刷新一次
    }

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(30);
        scheduler.setThreadNamePrefix("dynamic-scheduler-");
        scheduler.initialize();
        return scheduler;
    }
    /**
     * 刷新所有任务
     */
    private void refreshTasks() {
        try {
            List<ScheduledConfig> configs = scheduledConfigService.list();
            // 清理已删除的任务
            scheduledTasks.entrySet().removeIf(entry -> {
                String taskName = entry.getKey();
                return configs.stream()
                        .noneMatch(config -> config.getName().equals(taskName));
            });

            for (ScheduledConfig config : configs) {
                if (config.getCron() != null && !config.getCron().trim().isEmpty()) {
                    registerTask(config);
                }
            }
        } catch (Exception e) {
           log.error("刷新任务失败: " + e.getMessage());
            e.printStackTrace();
        }
    }


    /**
     * 注册单个任务
     */
    private void registerTask(ScheduledConfig config) {
        // 如果任务已存在，取消之前的任务
        ScheduledFuture<?> existingTask = scheduledTasks.get(config.getName());
        if (existingTask != null && !existingTask.isCancelled()) {
            existingTask.cancel(false);
        }

        Runnable task = () -> {
            try {
               log.info("执行任务: " + config.getName());
                executeBusinessLogic(config);
            } catch (Exception e) {
               log.error("任务执行失败: " + config.getName());
                e.printStackTrace();
            }
        };

        CronTrigger trigger = new CronTrigger(config.getCron());
        ScheduledFuture<?> scheduledTask = ((ThreadPoolTaskScheduler) taskScheduler).schedule(task, trigger);
        scheduledTasks.put(config.getName(), scheduledTask);
    }
    // 清理资源
    @PreDestroy
    public void cleanup() {
        scheduledTasks.values().forEach(task -> task.cancel(true));
        scheduledTasks.clear();
    }
    /**
     * 执行业务逻辑
     */
    @Async
    protected void executeBusinessLogic(ScheduledConfig config) {
        log.info("处理业务逻辑：" + config.getName());
        try {
            BusinessLogicService businessService = SpringContextUtil.getBean(BusinessLogicService.class);
            String methodName = config.getName();

            // 检查方法是否存在
            Method method = Arrays.stream(businessService.getClass().getMethods())
                    .filter(m -> m.getName().equals(methodName))
                    .findFirst()
                    .orElseThrow(() -> new NoSuchMethodException("执行方法没有:"+methodName));

            method.invoke(businessService);
        } catch (Exception e) {
            log.error("执行方法失败: " + config.getName());
            e.printStackTrace();
        }

    }

}
